package net.qiqb.module.spring;

import net.qiqb.module.ModuleContext;
import net.qiqb.module.dubbo.DubboServiceGateway;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SpringModuleContext extends ModuleContext {

    private BeanFactory beanFactory;

    private static final Map<BeanDefinitionRegistry, ModuleContext> CTX = new ConcurrentHashMap<>();

    public static ModuleContext getInstance(BeanDefinitionRegistry registry) {
        final ModuleContext moduleContext = CTX.get(registry);
        if (moduleContext != null) {
            return moduleContext;
        }
        synchronized (SpringModuleContext.class) {
            final SpringModuleContext value = new SpringModuleContext();
            CTX.put(registry, value);
            ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
            value.beanFactory = beanFactory;
            value.addServiceDispatcher(new DubboServiceGateway(beanFactory));
            beanFactory.registerSingleton(SpringModuleContext.class.getName(), value);
            // 注册 ModulePostProcessor
            RootBeanDefinition beanDefinition = new RootBeanDefinition(ModulePostProcessor.class);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            registry.registerBeanDefinition(ModulePostProcessor.class.getName(), beanDefinition);

            return value;
        }
    }


    private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {
        ConfigurableListableBeanFactory beanFactory;
        if (registry instanceof ConfigurableListableBeanFactory) {
            beanFactory = (ConfigurableListableBeanFactory) registry;
        } else if (registry instanceof GenericApplicationContext genericApplicationContext) {
            beanFactory = genericApplicationContext.getBeanFactory();
        } else {
            throw new IllegalStateException("Can not find Spring BeanFactory from registry: " + registry.getClass().getName());
        }
        return beanFactory;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }
}
